
import json
import logging
import os
import time
from datetime import datetime

from kubernetes import client, config
from nacos import NacosClient
import requests
from typing import Dict, List, Set, Optional


class PodNacosMonitor:
    def __init__(self):
        self.init_kubernetes_client()
        self.namespaces = self.parse_namespaces_config()
        self.nacos_client = self.init_nacos_client()

        self.logger = logging.getLogger(__name__)
        self.logger.info("Initializing EnhancedPodMonitor...")

        # 监控参数
        self.check_interval = int(os.getenv("CHECK_INTERVAL", "30"))
        self.abnormal_threshold = int(os.getenv("ABNORMAL_THRESHOLD", "5")) * 60

        # 异常记录 {namespace: {pod_ip: abnormal_data}}
        self.abnormal_pods: Dict[str, Dict[str, Dict]] = {}

        # 企微配置
        self.wecom_webhook = os.getenv("WECOM_WEBHOOK")
        self.wecom_mentioned = os.getenv("WECOM_MENTIONED", "").split(",")
    def init_kubernetes_client(self):
        try:
            config.load_incluster_config()
        except:
            config.load_kube_config()
        self.k8s_api = client.CoreV1Api()
    def init_nacos_client(self):
        return NacosClient(
            server_addresses=os.getenv("NACOS_SERVERS", "xxx:32564"),
            namespace=os.getenv("NACOS_NAMESPACE", "kfys-xls-oms-wms-test"),
            username=os.getenv("NACOS_USER", "dev"),
            password=os.getenv("NACOS_PASS", "Dxx")
        )

    def parse_namespaces_config(self) -> Set[str]:
        """解析Namespace配置"""
        namespaces = os.getenv("WATCH_NAMESPACES", "default")
        return {ns.strip() for ns in namespaces.split(",") if ns.strip()}

    def check_all_namespaces(self):
        """检查所有配置的namespace"""
        for ns in self.namespaces:
            try:
                self.check_namespace_pods(ns)
            except Exception as e:
                print(f"Error checking namespace {ns}: {str(e)}")

    def check_namespace_pods(self, namespace: str):
        """检查单个namespace下的pod状态"""
        print(f"checking namespace {namespace} pods")
        pods = self.k8s_api.list_namespaced_pod(namespace=namespace)
        current_time = time.time()

        if namespace not in self.abnormal_pods:
            self.abnormal_pods[namespace] = {}

        active_ips = set()

        for pod in pods.items:
            pod_ip = pod.status.pod_ip
            if not pod_ip:  # 跳过未分配IP的Pod
                continue

            active_ips.add(pod_ip)
            pod_name = pod.metadata.name

            is_abnormal = self.is_pod_abnormal(pod)

            if is_abnormal:
                self.handle_abnormal_pod(namespace, pod_ip, pod_name, current_time)
            else:
                self.handle_normal_pod(namespace, pod_ip)

        self.cleanup_removed_pods(namespace, active_ips)
    def handle_normal_pod(self, namespace: str, pod_ip: str):
        """处理恢复正常的pod"""
        if pod_ip in self.abnormal_pods[namespace]:
            del self.abnormal_pods[namespace][pod_ip]
            print(f"Pod {pod_ip} in namespace {namespace} returned to normal")
    def cleanup_removed_pods(self, namespace: str, active_ips: Set[str]):
        """清理已删除的pod记录"""
        for pod_ip in list(self.abnormal_pods[namespace].keys()):
            if pod_ip not in active_ips:
                del self.abnormal_pods[namespace][pod_ip]

    def is_pod_abnormal(self, pod) -> bool:
        """判断Pod是否异常"""
        return (
                pod.status.phase != "Running" or
                not all(
                    condition.status == "True"
                    for condition in pod.status.conditions
                    if condition.type == "Ready"
                )
        )

    def handle_abnormal_pod(self, namespace: str, pod_ip: str, pod_name: str, current_time: float):
        """处理异常pod"""
        if pod_ip not in self.abnormal_pods[namespace]:
            self.abnormal_pods[namespace][pod_ip] = {
                "start_time": current_time,
                "reported": False,
                "pod_name": pod_name
            }
        else:
            record = self.abnormal_pods[namespace][pod_ip]
            if not record["reported"] and (current_time - record["start_time"]) >= self.abnormal_threshold:
                if self.is_service_still_registered(pod_ip):
                    self.send_alert(namespace, pod_ip, record["pod_name"])
                    self.abnormal_pods[namespace][pod_ip]["reported"] = True

    def is_service_still_registered(self, pod_ip: str) -> bool:
        """检查该IP在Nacos中是否有健康服务"""
        try:
            # 获取Nacos中所有服务
            services = self.nacos_client.list_services()

            for service in services:
                instances = self.nacos_client.list_naming_instance(
                    service_name=service,
                    group_name="DEFAULT_GROUP"
                )
                if any(
                        instance["ip"] == pod_ip
                        and instance["healthy"]
                        for instance in instances.get("hosts", [])
                ):
                    return True
            return False
        except Exception as e:
            print(f"Error checking nacos registration for IP {pod_ip}: {str(e)}")
            return False

    def send_alert(self, namespace: str, pod_ip: str, pod_name: str):
        """发送告警信息"""
        if not self.wecom_webhook:
            return

        mentioned = " ".join(f"<@{user}>" for user in self.wecom_mentioned if user)

        message = {
            "msgtype": "markdown",
            "markdown": {
                "content": f"**服务状态异常告警**\n"
                           f"> 命名空间: `{namespace}`\n"
                           f"> Pod名称: `{pod_name}`\n"
                           f"> Pod IP: `{pod_ip}`\n"
                           f"> 异常持续时间: `{self.abnormal_threshold // 60}分钟`\n\n"
                           f"**当前状态**:\n"
                           f"- K8s Pod状态异常\n"
                           f"- Nacos中该IP(`{pod_ip}`)仍有健康服务注册\n\n"
                           f"{mentioned}\n\n"
                           f"**排查命令**:\n"
                           f"```bash\n"
                           f"kubectl logs -n {namespace} {pod_name}\n"
                           f"kubectl describe pod -n {namespace} {pod_name}\n"
                           f"```"
            }
        }

        try:
            resp = requests.post(self.wecom_webhook, json=message, timeout=5)
            print(f"Alert sent for {pod_ip}, response: {resp.text}")
        except Exception as e:
            print(f"Failed to send alert: {str(e)}")

    def start_monitoring(self):
        """启动监控"""
        # print(f"Starting monitor for namespaces: {', '.join(self.namespaces)}")
        while True:
            self.check_all_namespaces()
            time.sleep(self.check_interval)


if __name__ == "__main__":
    monitor = PodNacosMonitor()
    monitor.start_monitoring()